package xmlGen;

import java.io.FileOutputStream;
import java.io.IOException;
import java.text.ParseException;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import modele.Anniv;
import modele.Contact;
import modele.Event;
import modele.Reunion;
import modele.User;

import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import executer.Parser;
import java.util.SortedMap;
import java.util.TreeMap;


public class JDomParser {

	private Element root;
	
	/**
	 * Initialise la racine a partir de laquelle
	 * on commence le parsing
	 * 
	 * @param root {@link Element} a partir de laquelle on parse
	 */
	public JDomParser(Element root) {
		
		this.root = root;
	}
	
	/**
	 * Initialise la racine a null
	 */
	public JDomParser() {
		root = null;
	}


	/**
	 * Renvoie une {@link Map} de contact
	 * @return Retourne tous les contacts du owner
	 */
	@SuppressWarnings("unchecked")
	public Map<String, Contact> getContacts() {
		
		Map<String, Contact> contacts = new HashMap<String, Contact>();
		Iterator it = root.getChildren().iterator();
		while(it.hasNext()) {
			Contact courant = parseContact((Element)it.next());
			contacts.put(Integer.toString(courant.getId()), courant);
		}
		
		return contacts;
	}
	
	/**
	 * Cree un fichier XML contenant
	 * que les contacts pour leurs exportations
	 * @param fichier {@link String} nom du fichier de sauvegarde
	 */
	@SuppressWarnings("unchecked")
	public void contactsXML(String fichier) {
		
		Element racine = new Element("Contacts");
		Iterator it = root.getChildren().iterator();
		while(it.hasNext()) {
			Element elt = (Element)it.next();
			racine.addContent(parseXMLContact(elt));
		}
		Document doc = new Document(racine);

		try {
			XMLOutputter sortie = new XMLOutputter(Format.getPrettyFormat());
			sortie.output(doc, new FileOutputStream(fichier));
		} catch (IOException e) {
		}
	}
	
	
	/**
	 * Renvoie une {@link Map} d'evenemnets
	 * @return Retourne tous les evenements du owner
	 */
	@SuppressWarnings("unchecked")
	public Map<String, modele.Event> getEvents() {
		
		Map<String, Event> events = new HashMap<String, Event>();
		Iterator it = root.getChildren().iterator();
		
		while(it.hasNext()) {
			Event courant = parseEvent((Element)it.next());
			events.put(Integer.toString(courant.getId()), courant);
		}
		
		return events;
	}
	

	/**
	 * Parse l'element recu en parametre en {@link Event}
	 * 
	 * @param next {@link Element} correspondant a l'evenement
	 * @return un {@link Event}
	 */
	@SuppressWarnings("deprecation")
	private Event parseEvent(Element next) {
		
		String comment = next.getChildText("Commentaire");
		String desc = next.getAttributeValue("type");
		
		Event event;
		if(desc.equals("Anniversaire")) {
			User owner = parseUser(next.getChild("User"));
			event = new Anniv(Integer.parseInt(next.getAttributeValue("idEvent")),owner, comment);
		} else {
			Date date = new Date();
			try {
				date = Parser.parseToDate(next.getChildText("Date"));
			} catch (ParseException e) {
				e.printStackTrace();
			}
			int id = Integer.parseInt(next.getAttributeValue("idEvent"));
			event = new Reunion(id, date.getYear(), date.getMonth(), date.getDate(),
								date.getHours(), date.getMinutes(), desc, comment);
		}
		return event;
	}
	
	/**
	 * Readapte le format XML du contact
	 * et retourne la copie
	 * @param contact {@link Element} contenant les details du contact
	 * @return {@link Element} readapte
	 */
	private Element parseXMLContact(Element contact) {
		
		Element xml = new Element("Contact");
		Element child = new Element("Nom"); 
		child.addContent(contact.getChildText("Nom"));
		xml.addContent(child);
		child = new Element("Prenom"); 
		child.addContent(contact.getChildText("Prenom"));
		xml.addContent(child);
		child = new Element("Portable"); 
		child.addContent(contact.getChild("Telephone").getChildText("Portable"));
		xml.addContent(child);
		child = new Element("Fixe"); 
		child.addContent(contact.getChild("Telephone").getChildText("Fixe"));
		xml.addContent(child);
		child = new Element("Email"); 
		child.addContent(contact.getChildText("Email"));
		xml.addContent(child);
		xml.setAttribute(new Attribute("id", contact.getAttributeValue("id")));
		String adresse = "";
		adresse += contact.getChildText("Adresse") + " ";
		adresse += contact.getChildText("Ville") + " ";
		adresse += contact.getChildText("Pays");
		xml.addContent((new Element("Adresse")).addContent(adresse));
		
		return xml;
	}


	/**
	 * Renvoi le contact dont l'id est specifie en parametre
	 * @param id {@link String} correspond au contact
	 * @return Retourne le contact
	 */
	@SuppressWarnings("unchecked")
	public Contact getContact(String id) {
		
		Iterator it = root.getChildren().iterator();
		while(it.hasNext()) {
			Element courant = (Element)it.next();
			if(courant.getAttributeValue("id").equals(id)) {
				return parseContact(courant);
			}
		}
		
		return null;
	}
	
	
	/**
	 * Renvoi l'evenement dont l'id est specifie en parametre
	 * @param id {@link String} correspond a l'evenement
	 * @return Retourne l'evenement
	 */
	@SuppressWarnings("unchecked")
	public Event getEvent(String idEvent) {
		
		Iterator it = root.getChildren().iterator();
		while(it.hasNext()) {
			Element courant = (Element)it.next();
			if(courant.getAttributeValue("idEvent").equals(idEvent)) {
				return parseEvent(courant);
			}
		}
		
		return null;
	}

    /**
	 * Renvoi les evenements dont la date est specifie en parametre
	 * @param date {@link String} correspond aux evenements
	 * @return Retourne une map triee d'evenements
	 */
    @SuppressWarnings("unchecked")
	public Event[] getEventsByDate(String date) {

		Iterator it = root.getChildren().iterator();
        SortedMap<String, Event> mapEvent = new TreeMap<String, Event>();
        
		while(it.hasNext()) {
			Element courant = (Element)it.next();
			if(courant.getChildText("Date").contains(date)) {
                mapEvent.put(courant.getChildText("Date"), parseEvent(courant));
			}
		}
        System.out.println("taille : "+mapEvent.size());
        Collection<modele.Event> value = mapEvent.values();
        Object ob[] = value.toArray();
        Event event[] = new Event[ob.length];
        for (int i=0;i<ob.length;i++)
        	event[i]=(Event)ob[i];
	return event;
	}
	
	/**
	 * Parse l'element recu en parametre en {@link Contact}
	 * 
	 * @param next {@link Element} correspondant au contact
	 * @return un {@link Contact}
	 */
	private Contact parseContact(Element next) {
		
		Contact contact = new Contact();
		
		contact.setId(Integer.parseInt(next.getAttributeValue("id")));
		contact.setNom(next.getChildText("Nom"));
		contact.setPrenom(next.getChildText("Prenom"));
		contact.setAdresse(next.getChildText("Adresse"));
		contact.setVille(next.getChildText("Ville"));
		contact.setPays(next.getChildText("Pays"));
		contact.setFixe(next.getChild("Telephone").getChildText("Fixe"));
		contact.setPortable(next.getChild("Telephone").getChildText("Portable"));
		contact.setEmail(next.getChildText("Email"));
		
		return contact;
	}
	
	/**
	 * Parse l'element recu en {@link User} 
	 * 
	 * @param next {@link Element} correspond au user
	 * @return un {@link User}
	 */
	private User parseUser(Element next) {
		
		try {
			String nom = next.getChildText("Nom");
			String prenom = next.getChildText("Prenom");
			Date birthDay = Parser.parseToDate(next.getChildText("BirthDay"));
			return new User(nom, prenom, birthDay);
		} catch (ParseException e) {
			return null;
		}
	}


	/**
	 * Mets a jour le root
	 * @param root {@link Element} racine
	 */
	public void setRoot(Element root) {
		
		this.root = root;
	}
	
	
	/**
	 * Retourne le derenier idEvent qui a �t� enregistr�
	 * 
	 * @return idEvent max (ou dernier enregistr�)
	 */
	public int getLastIdEvent() {
		
		Set<String> keys = getEvents().keySet();
		int maxId = -1;
		
		for(String k: keys) {
			int value = Integer.parseInt(k); 
			if(value > maxId) {
				maxId = value;
			}
		}
		
		return maxId;
	}
	
	
	/**
	 * Retourne le derenier idContact qui a �t� enregistr�
	 * 
	 * @return idContact max (ou dernier enregistr�)
	 */
	public int getLastIdContact() {
		
		Set<String> keys = getContacts().keySet();
		int maxId = -1;
		
		for(String k: keys) {
			int value = Integer.parseInt(k); 
			if(value > maxId) {
				maxId = value;
			}
		}
		
		return maxId;
	}
}
